package com.eastfair.imaster.service.impl;

import cn.hutool.core.bean.BeanUtil;
import com.baomidou.dynamic.datasource.annotation.DS;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.toolkit.SqlHelper;
import com.eastfair.boot.request.PageParams;
import com.eastfair.boot.service.SuperCacheServiceImpl;
import com.eastfair.cache.operations.ConferenceCacheKeyBuilder;
import com.eastfair.config.api.ConfigServiceFeign;
import com.eastfair.config.dto.AttachmentDTO;
import com.eastfair.config.vo.AttachmentVO;
import com.eastfair.constant.BusinessConstant;
import com.eastfair.constant.EntityAttributeString;
import com.eastfair.core.base.R;
import com.eastfair.core.base.entity.SuperEntity;
import com.eastfair.core.context.ContextUtil;
import com.eastfair.core.exception.code.ExceptionCode;
import com.eastfair.core.model.CacheKeyBuilder;
import com.eastfair.core.utils.ConvertUtil;
import com.eastfair.core.utils.StringUtils;
import com.eastfair.enums.BusinessTypeEnum;
import com.eastfair.imaster.dao.ConferenceMapper;
import com.eastfair.imaster.dto.ConferenceDTO;
import com.eastfair.imaster.dto.ConferencePageQuery;
import com.eastfair.imaster.entity.Conference;
import com.eastfair.imaster.service.*;
import com.eastfair.imaster.vo.ConferenceVO;
import com.eastfair.projectcore.api.ProjectCoreServiceFeign;
import com.eastfair.core.snowflake.DefaultUidGenerator;
import io.seata.spring.annotation.GlobalTransactional;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.List;
import java.util.Objects;

/**
 * <p>
 * 业务实现类
 * 论坛表
 * </p>
 *
 * @author zjn
 * @date 2021-08-31
 */
@Slf4j
@Service
@DS("#thread.tenant")
public class ConferenceServiceImpl extends SuperCacheServiceImpl<ConferenceMapper, Conference> implements ConferenceService {

    @Autowired
    ProjectCoreServiceFeign projectCoreServiceFeign;
    @Autowired
    private ConferenceSpeakerService conferenceSpeakerService;
    @Autowired
    private SelfAttachmentService selfAttachmentService;
    @Autowired
    private ConfigServiceFeign configServiceFeign;
    @Autowired
    private SpeakerService speakerService;
    @Autowired
    private ConferenceTopicService conferenceTopicService;

    @Override
    protected CacheKeyBuilder cacheKeyBuilder() {
        return new ConferenceCacheKeyBuilder();
    }

    /**************sharding 分库分表操作 *****************/
    @Override
    public boolean updateByIdOfShard(Conference entity) {
        UpdateWrapper<Conference> updateWrapper = new UpdateWrapper<>();
        //可将指定字段更新为null
        updateWrapper.lambda().eq(Conference::getProjectId, ContextUtil.getProjectId()).eq(Conference::getId, entity.getId());
        entity.setProjectId(null);
        //删除缓存
        delCache(entity);
        return SqlHelper.retBool(this.getBaseMapper().update(entity, updateWrapper));
    }

    /**
     * 处理新增相关处理
     *
     * @param model 实体
     * @return 是否成功
     */
    @Override
    protected R<Boolean> handlerSave(Conference model) {
        //雪花ID
        model.setId(DefaultUidGenerator.getUidOfProjectId(ContextUtil.getProjectId()));
        model.setProjectId(ContextUtil.getProjectId());
        return R.successDef();
    }

    @Override
    @GlobalTransactional(name = "saveConference", rollbackFor = Exception.class)
    public R<Boolean> saveConference(ConferenceDTO conferenceDTO) {
        if (StringUtils.isBlank(conferenceDTO.getName(), conferenceDTO.getSortOrderType())) {
            return R.fail(ExceptionCode.ERROR_NULL_PARAMS);
        }
        Conference conference = BeanUtil.copyProperties(conferenceDTO, Conference.class);
        save(conference);

        // 新增嘉宾
        if (conferenceDTO.getConferenceSpeakerDTOList() != null && !conferenceDTO.getConferenceSpeakerDTOList().isEmpty()) {
            conferenceSpeakerService.saveConferenceSpeakers(conferenceDTO.getConferenceSpeakerDTOList(), conference.getId());
        }

        // 新增附件
        if (conferenceDTO.getAttachmentDTOList() != null && !conferenceDTO.getAttachmentDTOList().isEmpty()) {
            selfAttachmentService.saveAttachments(conferenceDTO.getAttachmentDTOList(), BusinessTypeEnum.CONFERENCE, conference.getId());
        }

        return R.successDef();
    }

    @Override
    @GlobalTransactional(name = "deleteById", rollbackFor = Exception.class)
    public R<Boolean> deleteById(Long id) {
        if (Objects.isNull(id)) {
            return R.fail(ExceptionCode.ERROR_NULL_ID);
        }
        Conference conference = Conference.builder().id(id).isDeleted(BusinessConstant.DELETE_YES).build();
        updateByIdOfShard(conference);

        // 删除关联嘉宾
        conferenceSpeakerService.deleteByConferenceId(id);

        // 删除附件
        configServiceFeign.deleteByBusiness(AttachmentDTO.builder().businessType(BusinessTypeEnum.CONFERENCE.name()).businessId(id).build());

        // 删除论坛主题关系
        conferenceTopicService.deleteTopicRelation(id);

        return R.successDef();
    }

    @Override
    @GlobalTransactional(name = "updateById", rollbackFor = Exception.class)
    public R<Boolean> updateById(ConferenceDTO conferenceDTO) {
        if (conferenceDTO == null || conferenceDTO.getId() == null) {
            return R.fail(ExceptionCode.ERROR_NULL_PARAMS);
        }

        // 修改嘉宾
        if (conferenceDTO.getConferenceSpeakerDTOList() == null || conferenceDTO.getConferenceSpeakerDTOList().isEmpty()) {
            // 删除原嘉宾
            conferenceSpeakerService.deleteByConferenceId(conferenceDTO.getId());
        } else {
            conferenceSpeakerService.deleteAndSaveConferenceSpeakers(conferenceDTO.getConferenceSpeakerDTOList(), conferenceDTO.getId());
        }

        // 修改附件
        if (conferenceDTO.getAttachmentDTOList() == null || conferenceDTO.getAttachmentDTOList().isEmpty()) {
            // 删除原附件
            AttachmentDTO attachmentDTO = AttachmentDTO.builder().businessType(BusinessTypeEnum.CONFERENCE.name())
                    .businessId(conferenceDTO.getId()).build();
            configServiceFeign.deleteByBusiness(attachmentDTO);
        } else {
            // 先删后插
            List<AttachmentDTO> attachmentDTOList = selfAttachmentService.convertAttachments(conferenceDTO.getAttachmentDTOList(), BusinessTypeEnum.CONFERENCE, conferenceDTO.getId());
            configServiceFeign.deleteAndSaveAttachmentList(attachmentDTOList);
        }

        //修改论坛
        return R.success(updateByIdOfShard(BeanUtil.copyProperties(conferenceDTO, Conference.class)));
    }

    @Override
    public R<ConferenceVO> queryById(Long id) {
        if (id == null) {
            return R.fail(ExceptionCode.ERROR_NULL_ID);
        }
        QueryWrapper<Conference> queryWrapper = new QueryWrapper<>();
        queryWrapper.lambda().eq(Conference::getProjectId, ContextUtil.getProjectId()).eq(Conference::getId, id)
                .eq(Conference::getIsDeleted, BusinessConstant.DELETE_NO);
        ConferenceVO conferenceVO = BeanUtil.copyProperties(getOne(queryWrapper, false), ConferenceVO.class);

        //拼接嘉宾详情
        conferenceVO.setConferenceSpeakerVOList(conferenceSpeakerService.getByConferenceId(id, conferenceVO.getSortOrderType()).getData());

        // 拼接附件详情
        List<AttachmentVO> attachmentVOList = configServiceFeign.getAttachmentListByBusiness(AttachmentDTO.builder().businessType(BusinessTypeEnum.CONFERENCE.name())
                .businessId(id).build()).getData();
        conferenceVO.setAttachmentvOList(attachmentVOList);
        return R.success(conferenceVO);
    }

    @Override
    public Page<ConferenceVO> queryPageList(PageParams<ConferencePageQuery> params) {
        Conference conference = BeanUtil.copyProperties(params.getModel(), Conference.class);
        QueryWrapper<Conference> conferenceQueryWrapper = buildListBaseWrapper(conference);
        return ConvertUtil.convertPage(page(params.buildPage(), conferenceQueryWrapper), ConferenceVO.class);
    }

    @Override
    public List<ConferenceVO> queryList(ConferenceDTO conferenceDTO) {
        Conference conference = BeanUtil.copyProperties(conferenceDTO, Conference.class);
        QueryWrapper<Conference> conferenceQueryWrapper = buildListBaseWrapper(conference);
        return ConvertUtil.convertList(list(conferenceQueryWrapper), ConferenceVO.class);
    }

    /**
     * 列表通用参数拼接方法
     *
     * @param conference
     * @return
     */
    private QueryWrapper<Conference> buildListBaseWrapper(Conference conference) {
        QueryWrapper<Conference> queryWrapper = new QueryWrapper<>();
        queryWrapper.lambda().eq(Conference::getProjectId, ContextUtil.getProjectId()).eq(Conference::getIsDeleted, BusinessConstant.DELETE_NO)
                .select(Conference.class, info -> !info.getColumn().equals(EntityAttributeString.INTRODUCE)
                        && !info.getColumn().equals(EntityAttributeString.EN_INTRODUCE))
                .orderByAsc(Conference::getSequence);

        if (conference.getIsShelves() != null) {
            queryWrapper.lambda().eq(Conference::getIsShelves, conference.getIsShelves());
        }

        if (!StringUtils.isBlank(conference.getName())) {
            queryWrapper.lambda().and(wrapper ->
                    wrapper.like(Conference::getName, conference.getName()).or().like(Conference::getEnName, conference.getName())
            );
        }
        return queryWrapper;
    }

    @Override
    @GlobalTransactional(name = "updateEnabledById", rollbackFor = Exception.class)
    public R<Boolean> updateEnabledById(ConferenceDTO conferenceDTO) {
        if (Objects.isNull(conferenceDTO) || Objects.isNull(conferenceDTO.getId()) || Objects.isNull(conferenceDTO.getIsEnabled())) {
            return R.fail(ExceptionCode.ERROR_NULL_PARAMS);
        }

        // 修改论坛
        UpdateWrapper<Conference> updateWrapper = new UpdateWrapper<>();
        updateWrapper.lambda().eq(SuperEntity::getId, conferenceDTO.getId()).eq(Conference::getProjectId, ContextUtil.getProjectId())
                .set(Conference::getIsEnabled, conferenceDTO.getIsEnabled());
        update(updateWrapper);

        // 修改论坛主题
        conferenceTopicService.updateEnabledByConferenceId(conferenceDTO.getId(), conferenceDTO.getIsEnabled());

        return R.success(Boolean.TRUE);
    }
}
